using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using GenResponseAuth;

namespace LibFetion
{
    public class FetionBase
    {
        private readonly FetionCommunicationManager commnunicationManager;
        private readonly CookieCollection cookieCollection;
        private readonly CookieContainer cookieContainer;
        private int callId;
        private string domain;
        private string mobileno;
        private string password;
        private int seq;
        private string sid;
        private string ssic;
        private string uri_self;
        private string user_status;

        public FetionBase()
        {
            commnunicationManager = new FetionCommunicationManager();
            cookieCollection = new CookieCollection();
            cookieContainer = new CookieContainer();
        }

        public int GetNextCallId()
        {
            return ++callId;
        }

        public string GetNextUrl(string t)
        {
            ++seq;
            return string.Format("{0}?t=s&i={1}", ConstValue.FETION_URL, seq);
        }

        public bool LogOn(string mobileNum, string password)
        {
            string logUrl = string.Format("{0}?mobileno={1}&pwd={2}", ConstValue.FETION_LOGIN_URL, mobileNum, password);
            this.password = password;
            Regex cookieRegex = new Regex("ssic=(.*);");
            Regex sidRegex = new Regex("sip:(\\d+)@(.+);");
            HttpWebRequest request = commnunicationManager.CreateFetionRequest(logUrl, null, null);
            ServicePointManager.ServerCertificateValidationCallback += CheckValidationResult;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            if (response != null)
            {
                string cookies = response.Headers[HttpResponseHeader.SetCookie];
                Match cookieMath = cookieRegex.Match(cookies);
                if (cookieMath.Success)
                {
                    cookieCollection.Add(new Cookie("ssic", cookieMath.Groups[1].Value));
                    ssic = cookieMath.Groups[1].Value;
                }

                XmlDocument responseDocument = new XmlDocument();
                StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                responseDocument.LoadXml(reader.ReadToEnd());
                XmlNode userNode = responseDocument.SelectSingleNode("results/user");
                uri_self = userNode.Attributes["uri"].Value;
                mobileno = userNode.Attributes["mobile-no"].Value;
                user_status = userNode.Attributes["user-status"].Value;
                Match sidMatch = sidRegex.Match(uri_self);
                if (sidMatch.Success)
                {
                    sid = sidMatch.Groups[1].Value;
                    domain = sidMatch.Groups[2].Value;
                }
                reader.Close();
                response.Close();
                return true;
            }
            return false;
        }

        public void GetSystemConfig()
        {
            const string args =
                "<args><device type=\"PC\" version=\"95\" client-version=\"3.1.0480\" /><caps value=\"simple-im;im-session;temp-group\" /><events value=\"contact;permission;system-message\" /><user-info attributes=\"all\" /><presence><basic value=\"400\" desc=\"\" /></presence></args>";
            HttpWebRequest request = commnunicationManager.CreateFetionRequest(ConstValue.FETION_CONFIG_URL, null, args);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        }

        public void Register()
        {
            const string args =
                "<args><device type=\"PC\" version=\"95\" client-version=\"3.1.0480\" /><caps value=\"simple-im;im-session;temp-group\" /><events value=\"contact;permission;system-message\" /><user-info attributes=\"all\" /><presence><basic value=\"400\" desc=\"\" /></presence></args>";
            SipMessage message = new SipMessage(SipMessageType.Register);
            int callIdNow = GetNextCallId();
            message.AddField(ConstValue.SipF, sid);
            message.AddField(ConstValue.SipI, callIdNow.ToString());
            message.AddField(ConstValue.SipQ, "1 R");
            message.Args = args;
            commnunicationManager.ConnectToServer();
            string returnText = commnunicationManager.Send(message.GetContent());
            Regex nonceRegex = new Regex("nonce=\"(.*)\"");
            Match nonceMatch = nonceRegex.Match(returnText);
            string nonce = "";
            if (nonceMatch.Success) nonce = nonceMatch.Groups[1].Value;
            ComputeAuthResponse computeAuthResponse = new ComputeAuthResponse(sid, password, domain, nonce, false);
            string cnonce = computeAuthResponse.GetCNonce();
            string response =
                computeAuthResponse.ComputeResponse();

            SipMessage message1 = new SipMessage(SipMessageType.Register);
            message1.AddField(ConstValue.SipF, sid);
            message1.AddField(ConstValue.SipI, callIdNow.ToString());
            message1.AddField(ConstValue.SipQ, "2 R");
            message1.AddField(ConstValue.SipA, "Digest response=\"" + response + "\",cnonce=\"" + cnonce + "\"");
            message1.Args = args;
            string returnText0 = commnunicationManager.Send(message1.GetContent());

            //GetPersonalInfo();
            //GetFriendsList();
        }

        public void GetFriendsList()
        {
            int callIdNow;
            callIdNow = GetNextCallId();
            const string args1 =
                "<args><contacts><buddy-lists /><buddies attributes=\"all\" /><mobile-buddies attributes=\"all\" /><chat-friends /><blacklist /></contacts></args>";
            SipMessage message3 = new SipMessage(SipMessageType.Service);
            message3.AddField(ConstValue.SipF, sid);
            message3.AddField(ConstValue.SipI, callIdNow.ToString());
            message3.AddField(ConstValue.SipQ, "1 S");
            message3.AddField(ConstValue.SipN, "GetContactList");
            message3.Args = args1;
            string returnText2 = commnunicationManager.Send(message3.GetContent());

            int xmlIndex = returnText2.IndexOf("\r\n\r\n") + 4;
            XmlDocument buddyXmldocument = new XmlDocument();
            buddyXmldocument.LoadXml(returnText2.Substring(xmlIndex));
            XmlNodeList buddys = buddyXmldocument.SelectNodes("results/contacts/buddies/buddy");
            for (int i = 0; i < buddys.Count; i++)
            {
                AddFriendsArgs addFriendsArgs = new AddFriendsArgs();
                addFriendsArgs.Uri = buddys[i].Attributes["uri"].Value;
                AddFriendsEvent(this, addFriendsArgs);
            }
            XmlNodeList mobile_buddys = buddyXmldocument.SelectNodes("results/contacts/mobile-buddies/mobile-buddy");
            for (int i = 0; i < mobile_buddys.Count; i++)
            {
                AddFriendsArgs addFriendsArgs = new AddFriendsArgs();
                addFriendsArgs.Uri = mobile_buddys[i].Attributes["uri"].Value;
                AddFriendsEvent(this, addFriendsArgs);
            }
        }

        public void GetPersonalInfo()
        {
            int callIdNow;
            callIdNow = GetNextCallId();
            const string args0 =
                "<args><personal attributes=\"all\" /><services version=\"\" attributes=\"all\" /><config version=\"96\" attributes=\"all\" /><mobile-device attributes=\"all\" /></args>";
            SipMessage message2 = new SipMessage(SipMessageType.Service);
            message2.AddField(ConstValue.SipF, sid);
            message2.AddField(ConstValue.SipI, callIdNow.ToString());
            message2.AddField(ConstValue.SipQ, "1 S");
            message2.AddField(ConstValue.SipN, "GetPersonalInfo");
            message2.Args = args0;
            string returnText1 = commnunicationManager.Send(message2.GetContent());
        }

        public void SendSMS(string msg)
        {
            int callIdNow = GetNextCallId();
            SipMessage message3 = new SipMessage(SipMessageType.SendMessage);
            message3.AddField(ConstValue.SipF, sid);
            message3.AddField(ConstValue.SipI, callIdNow.ToString());
            message3.AddField(ConstValue.SipQ, "1 M");
            message3.AddField(ConstValue.SipT, uri_self);
            message3.AddField(ConstValue.SipN, "SendCatSMS");
            message3.Args = msg;
            string returnText2 = commnunicationManager.Send(message3.GetContent());
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain,
                                                  SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }


        public delegate void AddFriends(object sender, AddFriendsArgs args);
        public event AddFriends AddFriendsEvent;
    }
    public class AddFriendsArgs : System.EventArgs
    {
        private string _uri;

        public string Uri
        {
            get { return _uri; }
            set { _uri = value; }
        }
    }
}